package com.example.icar.rosmaster;

import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Rosmaster客户端，用于与Rosmaster小车进行网络通信
 * 支持TCP和HTTP两种通信方式
 */
public class RosmasterHttpClient {
    private static final String TAG = "RosmasterHttpClient";
    
    private String ipAddress;
    private int port;
    private ExecutorService executorService;
    private boolean isConnected = false;
    private Socket tcpSocket = null;
    private boolean debug = false;
    
    // TCP连接的默认端口
    private static final int DEFAULT_TCP_PORT = 6000;
    
    /**
     * 构造函数
     * @param ipAddress IP地址
     * @param port 端口
     */
    public RosmasterHttpClient(String ipAddress, int port) {
        this(ipAddress, port, false);
    }
    
    /**
     * 构造函数
     * @param ipAddress IP地址
     * @param port 端口
     * @param debug 是否启用调试日志
     */
    public RosmasterHttpClient(String ipAddress, int port, boolean debug) {
        this.ipAddress = ipAddress;
        this.port = port;
        this.debug = debug;
        // 创建新的线程池，避免使用已关闭的线程池
        this.executorService = Executors.newCachedThreadPool();
        Log.d(TAG, "创建RosmasterClient，连接到: " + ipAddress + ":" + port + "，创建新线程池");
    }
    
    /**
     * 测试连接
     * @return 连接是否成功
     */
    public boolean testConnection() {
        // 确保线程池有效
        if (executorService == null || executorService.isShutdown()) {
            Log.d(TAG, "线程池已关闭，重新创建");
            executorService = Executors.newCachedThreadPool();
        }
        
        // 尝试多个常用端口
        int[] portsToTry = {DEFAULT_TCP_PORT, 6001, 6005, 6500, 8080};
        
        // 首先尝试TCP连接
        for (int testPort : portsToTry) {
            try {
                Log.d(TAG, "尝试TCP连接到端口: " + testPort);
                Socket socket = new Socket();
                socket.connect(new java.net.InetSocketAddress(ipAddress, testPort), 3000);
                
                // 尝试发送一个简单的命令
                try {
                    OutputStream out = socket.getOutputStream();
                    out.write("$0015040000#\n".getBytes());
                    out.flush();
                    Log.d(TAG, "TCP测试命令已发送");
                } catch (Exception e) {
                    Log.w(TAG, "发送测试命令失败: " + e.toString());
                    // 继续，不认为这是失败
                }
                
                socket.close();
                Log.d(TAG, "TCP连接测试成功（端口" + testPort + "）");
                
                // 如果连接成功，更新默认端口
                if (testPort != port) {
                    Log.d(TAG, "更新端口为: " + testPort);
                    this.port = testPort;
                }
                
                isConnected = true;
                return true;
            } catch (IOException e) {
                Log.e(TAG, "TCP连接测试失败（端口" + testPort + "）: " + e.toString());
            }
        }
        
        // 如果所有TCP连接都失败，尝试HTTP连接
        for (int testPort : new int[]{port, 8080, 8000, 80}) {
            try {
                URL url = new URL("http://" + ipAddress + ":" + testPort + "/");
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(3000);
                connection.setReadTimeout(3000);
                
                int responseCode = connection.getResponseCode();
                Log.d(TAG, "HTTP测试响应码: " + responseCode + " (端口" + testPort + ")");
                
                if (responseCode == HttpURLConnection.HTTP_OK || 
                    responseCode == HttpURLConnection.HTTP_ACCEPTED || 
                    responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
                    isConnected = true;
                    
                    // 更新端口
                    if (testPort != port) {
                        Log.d(TAG, "更新HTTP端口为: " + testPort);
                        this.port = testPort;
                    }
                    
                    return true;
                }
            } catch (IOException httpEx) {
                Log.e(TAG, "HTTP测试连接失败 (端口" + testPort + "): " + httpEx.toString());
            }
        }
        
        // 所有连接方式都失败
        isConnected = false;
        return false;
    }
    
    /**
     * 获取连接的IP地址
     * @return IP地址
     */
    public String getIpAddress() {
        return ipAddress;
    }
    
    /**
     * 获取连接的端口
     * @return 端口
     */
    public int getPort() {
        return port;
    }
    
    /**
     * 检查连接是否有效
     * @return 连接状态
     */
    public boolean isConnected() {
        return isConnected;
    }
    
    /**
     * 发送命令到Rosmaster
     * @param command 要发送的命令
     */
    public void sendCommand(String command) {
        // 先检查线程池是否已关闭
        if (executorService == null || executorService.isShutdown()) {
            Log.e(TAG, "无法发送命令：线程池已关闭");
            return;
        }
        
        try {
            executorService.execute(() -> {
                try {
                    // 判断是否为HTTP格式命令
                    boolean isHttpCommand = command.contains("?") && (
                        command.startsWith("move") || 
                        command.startsWith("servo") || 
                        command.startsWith("led"));
                    
                    if (isHttpCommand) {
                        // 将HTTP命令转换为TCP命令
                        String tcpCommand = convertHttpToTcp(command);
                        if (tcpCommand != null) {
                            // 发送TCP命令
                            sendTcpCommand(tcpCommand);
                        } else {
                            // 如果转换失败，尝试发送原始命令
                            Log.d(TAG, "无法将HTTP命令转换为TCP命令，尝试直接发送: " + command);
                            sendTcpCommand(command);
                        }
                    } else if (command.contains("|")) {
                        // 多命令格式，用|分隔，依次尝试每一种命令格式
                        String[] commands = command.split("\\|");
                        Log.d(TAG, "检测到多命令格式，将尝试 " + commands.length + " 种车型命令");
                        
                        for (String cmd : commands) {
                            if (!cmd.trim().isEmpty()) {
                                Log.d(TAG, "尝试发送命令: " + cmd.trim());
                                sendTcpCommand(cmd.trim());
                                
                                // 每个命令之间间隔200ms，避免命令冲突
                                try {
                                    Thread.sleep(200);
                                } catch (InterruptedException e) {
                                    Log.e(TAG, "线程休眠被中断: " + e.toString());
                                }
                            }
                        }
                    } else {
                        // 发送原始TCP命令
                        sendTcpCommand(command);
                    }
                } catch (Exception e) {
                    Log.e(TAG, "发送命令出错: " + e.toString());
                }
            });
        } catch (java.util.concurrent.RejectedExecutionException e) {
            Log.e(TAG, "命令被拒绝执行，线程池可能已关闭: " + e.toString());
        } catch (Exception e) {
            Log.e(TAG, "提交命令到线程池时出错: " + e.toString());
        }
    }
    
    /**
     * 将HTTP命令转换为TCP命令
     * @param httpCommand HTTP命令字符串
     * @return TCP命令字符串，如果无法转换则返回null
     */
    private String convertHttpToTcp(String httpCommand) {
        try {
            // 解析HTTP命令
            String[] parts = httpCommand.split("\\?");
            if (parts.length != 2) {
                return null;
            }
            
            String cmdType = parts[0];
            String params = parts[1];
            
            // 解析参数
            String[] paramPairs = params.split("&");
            
            if ("move".equals(cmdType)) {
                // 移动命令
                String direction = null;
                int speed = 0;
                
                for (String pair : paramPairs) {
                    String[] keyValue = pair.split("=");
                    if (keyValue.length == 2) {
                        if ("direction".equals(keyValue[0])) {
                            direction = keyValue[1];
                        } else if ("speed".equals(keyValue[0])) {
                            try {
                                speed = Integer.parseInt(keyValue[1]);
                            } catch (NumberFormatException e) {
                                Log.e(TAG, "解析速度参数出错: " + e.toString());
                            }
                        }
                    }
                }
                
                if (direction != null) {
                    int state;
                    // 尝试使用不同的小车类型
                    int[] carTypes = {1, 4, 5, 2};  // 依次尝试X1、X3_PLUS、X1_PLUS和可能的其他类型
                    
                    switch (direction) {
                        case "forward":
                            state = 1; // 前进
                            break;
                        case "backward":
                            state = 2; // 后退
                            break;
                        case "left":
                            state = 3; // 左转
                            break;
                        case "right":
                            state = 4; // 右转
                            break;
                        default:
                            state = 0; // 停止
                            break;
                    }
                    
                    // 尝试多种小车类型命令格式
                    for (int carType : carTypes) {
                        // 构建命令，格式：$TTFFLLDD...CC#
                        // TT: 小车类型, FF: 功能码, LL: 数据长度, DD: 数据, CC: 校验和
                        int checksum = (carType + 0x15 + 0x04 + state) % 256;
                        String command = String.format("$%02x%02x%02x%02x%02x#", 
                                carType, 0x15, 0x04, state, checksum);
                        
                        Log.d(TAG, "尝试小车类型 " + carType + " 的TCP命令: " + command);
                        
                        // 每种类型命令间隔一段时间发送，避免命令冲突
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            Log.e(TAG, "线程休眠被中断: " + e.toString());
                        }
                        
                        // 发送命令
                        sendTcpCommand(command);
                    }
                    
                    // 返回使用CARTYPE_X1的命令作为默认值
                    int carType = 1;
                    int checksum = (carType + 0x15 + 0x04 + state) % 256;
                    return String.format("$%02x%02x%02x%02x%02x#", 
                            carType, 0x15, 0x04, state, checksum);
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "转换HTTP命令出错: " + e.toString());
        }
        
        return null;
    }
    
    /**
     * 发送TCP命令
     * @param command 要发送的命令
     */
    private void sendTcpCommand(String command) {
        final int MAX_RETRIES = 3;
        int retryCount = 0;
        boolean success = false;
        
        while (!success && retryCount < MAX_RETRIES) {
            Socket socket = null;
            try {
                // 创建Socket连接
                socket = new Socket();
                socket.connect(new java.net.InetSocketAddress(ipAddress, DEFAULT_TCP_PORT), 3000);
                socket.setSoTimeout(3000);
                
                // 使用字节流直接发送命令，而不是PrintWriter
                byte[] commandBytes = command.getBytes();
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write(commandBytes);
                outputStream.flush();
                Log.d(TAG, "[尝试 " + (retryCount + 1) + "] 通过TCP发送命令字节: " + bytesToHex(commandBytes) + ", 原命令: " + command);
                
                // 尝试读取响应
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                char[] buffer = new char[1024];
                int bytesRead = reader.read(buffer, 0, buffer.length);
                if (bytesRead > 0) {
                    String response = new String(buffer, 0, bytesRead);
                    Log.d(TAG, "收到TCP响应: " + response);
                    // 如果收到响应，认为成功
                    success = true;
                } else {
                    Log.d(TAG, "未收到响应");
                    // 没有响应，但不一定失败，也视为成功
                    success = true;
                }
                
            } catch (java.net.ConnectException e) {
                Log.e(TAG, "连接被拒绝: " + e.toString());
                retryCount++;
                try {
                    // 等待一段时间后重试
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                    Log.e(TAG, "线程休眠被中断: " + ie.toString());
                }
            } catch (java.net.SocketTimeoutException e) {
                Log.e(TAG, "连接超时: " + e.toString());
                retryCount++;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                    Log.e(TAG, "线程休眠被中断: " + ie.toString());
                }
            } catch (IOException e) {
                Log.e(TAG, "发送TCP命令出错: " + e.toString());
                retryCount++;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                    Log.e(TAG, "线程休眠被中断: " + ie.toString());
                }
            } finally {
                if (socket != null && !socket.isClosed()) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        Log.e(TAG, "关闭Socket出错: " + e.toString());
                    }
                }
            }
        }
        
        if (!success) {
            Log.e(TAG, "发送命令失败，已尝试 " + MAX_RETRIES + " 次");
        }
    }
    
    /**
     * 发送HTTP命令到小车
     * @param command HTTP命令字符串
     * @return 响应结果
     */
    public String sendHttpCommand(String command) throws IOException {
        if (debug) {
            Log.d(TAG, "发送HTTP命令: " + command);
        }
        
        // 构建URL
        String urlString = "http://" + ipAddress + ":" + port + "/" + command;
        if (debug) {
            Log.d(TAG, "完整URL: " + urlString);
        }
        
        URL url = new URL(urlString);
        HttpURLConnection connection = null;
        
        try {
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(3000);  // 增加超时时间
            connection.setReadTimeout(3000);     // 增加超时时间
            connection.setRequestMethod("GET");
            connection.setDoInput(true);
            
            // 添加User-Agent头，有些服务器需要这个
            connection.setRequestProperty("User-Agent", "RosmasterApp/1.0");
            
            // 连接并获取响应码
            connection.connect();
            
            try {
                int responseCode = connection.getResponseCode();
                
                if (debug) {
                    Log.d(TAG, "HTTP响应码: " + responseCode);
                }
                
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                    String inputLine;
                    StringBuilder response = new StringBuilder();
                    
                    while ((inputLine = in.readLine()) != null) {
                        response.append(inputLine);
                    }
                    in.close();
                    
                    String result = response.toString();
                    if (debug) {
                        Log.d(TAG, "HTTP响应: " + result);
                    }
                    
                    return result;
                } else {
                    String errorMsg = "HTTP请求失败，响应码: " + responseCode;
                    Log.e(TAG, errorMsg);
                    
                    // 尝试读取错误流
                    try {
                        BufferedReader errorReader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
                        StringBuilder errorResponse = new StringBuilder();
                        String line;
                        while ((line = errorReader.readLine()) != null) {
                            errorResponse.append(line);
                        }
                        errorReader.close();
                        
                        if (errorResponse.length() > 0) {
                            Log.e(TAG, "错误响应内容: " + errorResponse.toString());
                        }
                    } catch (Exception e) {
                        Log.e(TAG, "读取错误流失败: " + e.getMessage());
                    }
                    
                    throw new IOException(errorMsg);
                }
            } catch (IOException e) {
                // 检查是否是TCP服务器欢迎消息导致的错误
                if (e.getMessage() != null && e.getMessage().contains("Welcome to Rosmaster TCP Server")) {
                    Log.d(TAG, "检测到TCP服务器欢迎消息，切换到TCP模式发送命令");
                    // 这是TCP服务器，不是HTTP服务器，切换到TCP模式
                    // 关闭当前连接
                    connection.disconnect();
                    
                    // 使用TCP发送命令
                    sendTcpCommand(command);
                    return "TCP_MODE_COMMAND_SENT";
                } else {
                    Log.e(TAG, "HTTP请求异常: " + e.getMessage());
                    throw e;
                }
            }
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
    
    /**
     * 将字节数组转换为十六进制字符串，用于日志输出
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02X ", b));
        }
        return result.toString();
    }
    
    /**
     * 关闭连接
     */
    public void close() {
        Log.d(TAG, "关闭RosmasterClient连接");
        isConnected = false;
        
        if (tcpSocket != null && !tcpSocket.isClosed()) {
            try {
                tcpSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "关闭TCP Socket出错: " + e.toString());
            }
            tcpSocket = null;
        }
        
        if (executorService != null) {
            try {
                // 使用shutdownNow立即关闭所有任务
                List<Runnable> pendingTasks = executorService.shutdownNow();
                Log.d(TAG, "线程池关闭，有 " + pendingTasks.size() + " 个任务未执行");
                
                // 等待线程池终止，但设置较短的超时时间
                boolean terminated = executorService.awaitTermination(500, TimeUnit.MILLISECONDS);
                if (!terminated) {
                    Log.w(TAG, "线程池未在规定时间内终止");
                }
            } catch (InterruptedException e) {
                Log.e(TAG, "等待线程池终止时被中断: " + e.toString());
                Thread.currentThread().interrupt(); // 重设中断标志
            } catch (Exception e) {
                Log.e(TAG, "关闭线程池时出错: " + e.toString());
            }
            executorService = null;
        }
    }
} 